using System;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Text;
using System.Workflow.ComponentModel;
using System.Workflow.ComponentModel.Design;
using OpenComposite.Workflow;

namespace OpenComposite.EII.Designer.Workflow
{
	internal sealed class IdentifierCreationService : IIdentifierCreationService
	{
		private IServiceProvider serviceProvider = null;

		internal IdentifierCreationService(IServiceProvider serviceProvider)
		{
			this.serviceProvider = serviceProvider;
		}

		void IIdentifierCreationService.ValidateIdentifier(Activity activity, string identifier)
		{
			if ( identifier == null )
				throw new ArgumentNullException("identifier");
			if ( activity == null )
				throw new ArgumentNullException("activity");

			if ( activity.Name.ToLower().Equals(identifier.ToLower()) )
				return;

			Microsoft.CSharp.CSharpCodeProvider codeProvider = new Microsoft.CSharp.CSharpCodeProvider();
			if ( !codeProvider.IsValidIdentifier(identifier) ) {
				identifier = activity.Name;
				throw new ArgumentException(string.Format("Invalid identifier '{0}'}", identifier), "identifier");
				//System.Windows.Forms.MessageBox.Show(string.Format("Invalid Component Identifier \"{0}\"", identifier), activity.Name, System.Windows.Forms.MessageBoxButtons.OK, System.Windows.Forms.MessageBoxIcon.Error);
				//identifier = activity.Name;
				//return;
			}

			ArrayList identifiers = new ArrayList();
			Activity rootActivity = Helpers.GetRootActivity(activity);
			//identifiers.AddRange(GetIdentifiersInCompositeActivity(rootActivity as CompositeActivity));
			identifiers.AddRange(WorkflowHelpers.GetChildActivityNames(rootActivity as CompositeActivity));
			identifiers.Sort();
			if ( identifiers.BinarySearch(identifier.ToLower(), StringComparer.OrdinalIgnoreCase) >= 0 )
				throw new ArgumentException(string.Format("Duplicate Component Identifier \"{0}\"", identifier));
		}

		void IIdentifierCreationService.EnsureUniqueIdentifiers(CompositeActivity parentActivity, ICollection childActivities)
		{
			if ( parentActivity == null )
				throw new ArgumentNullException("parentActivity");
			if ( childActivities == null )
				throw new ArgumentNullException("childActivities");

			foreach ( object obj in childActivities ) {
				Activity act = obj as Activity;
				if ( act == null ) continue;
				act.Name = WorkflowHelpers.EnsureUniqueName(parentActivity, act.Name);
			}

			//List<Activity> allActivities = new List<Activity>();

			//Queue activities = new Queue(childActivities);
			//while ( activities.Count > 0 ) {
			//    Activity activity = (Activity)activities.Dequeue();
			//    if ( activity is CompositeActivity ) {
			//        foreach ( Activity child in ( (CompositeActivity)activity ).Activities )
			//            activities.Enqueue(child);
			//    }

			//    //If we are moving activities, we need not regenerate their identifiers
			//    if ( ( (IComponent)activity ).Site != null )
			//        continue;

			//    allActivities.Add(activity);
			//}

			//// get the root activity
			//CompositeActivity rootActivity = Helpers.GetRootActivity(parentActivity) as CompositeActivity;
			//ArrayList identifiers = new ArrayList(); // all the identifiers in the workflow
			//identifiers.AddRange(GetIdentifiersInCompositeActivity(rootActivity));

			//foreach ( Activity activity in allActivities ) {
			//    string finalIdentifier = activity.Name;

			//    // now loop until we find a identifier that hasn't been used.
			//    string baseIdentifier = GetBaseIdentifier(activity);
			//    //string baseIdentifier = activity.Name;
			//    int index = 0;

			//    identifiers.Sort();
			//    while ( finalIdentifier == null || finalIdentifier.Length == 0 || identifiers.BinarySearch(finalIdentifier.ToLower(), StringComparer.OrdinalIgnoreCase) >= 0 ) {
			//        finalIdentifier = string.Format("{0}{1}", baseIdentifier, ++index);
			//    }

			//    // add new identifier to collection 
			//    identifiers.Add(finalIdentifier);
			//    activity.Name = finalIdentifier;
			//}
		}

		private static IList GetIdentifiersInCompositeActivity(CompositeActivity compositeActivity)
		{
		//    ArrayList identifiers = new ArrayList();
		//    if ( compositeActivity != null ) {
		//        identifiers.Add(compositeActivity.Name);
		//        IList<Activity> allChildren = GetAllNestedActivities(compositeActivity);
		//        foreach ( Activity activity in allChildren )
		//            identifiers.Add(activity.Name);
		//    }
			return ArrayList.ReadOnly(WorkflowHelpers.GetChildActivityNames(compositeActivity));
		}

		private static string GetBaseIdentifier(Activity activity)
		{
			string baseIdentifier = activity.GetType().Name;
			StringBuilder b = new StringBuilder(baseIdentifier.Length);
			for ( int i = 0; i < baseIdentifier.Length; i++ ) {
				if ( Char.IsUpper(baseIdentifier[i]) && ( i == 0 || i == baseIdentifier.Length - 1 || Char.IsUpper(baseIdentifier[i + 1]) ) ) {
					b.Append(Char.ToLower(baseIdentifier[i]));
				} else {
					b.Append(baseIdentifier.Substring(i));
					break;
				}
			}
			return b.ToString();
		}

		private static Activity[] GetAllNestedActivities(CompositeActivity compositeActivity)
		{
			if ( compositeActivity == null )
				throw new ArgumentNullException("compositeActivity");

			ArrayList nestedActivities = new ArrayList();
			Queue compositeActivities = new Queue();
			compositeActivities.Enqueue(compositeActivity);
			while ( compositeActivities.Count > 0 ) {
				CompositeActivity compositeActivity2 = (CompositeActivity)compositeActivities.Dequeue();

				foreach ( Activity activity in compositeActivity2.Activities ) {
					nestedActivities.Add(activity);
					if ( activity is CompositeActivity )
						compositeActivities.Enqueue(activity);
				}

				foreach ( Activity activity in compositeActivity2.EnabledActivities ) {
					if ( !nestedActivities.Contains(activity) ) {
						nestedActivities.Add(activity);
						if ( activity is CompositeActivity )
							compositeActivities.Enqueue(activity);
					}
				}
			}
			return (Activity[])nestedActivities.ToArray(typeof(Activity));
		}
	}
}
